package fem2;

import math2.FunctionRnToR;
import math2.UnitFunctionRnToR;

/**
 * The <code>Constraint</code> class provides the method to check whether an FE
 * object is fixed or free.
 * 
 * @author hbui
 */

public class Constraint implements Cloneable {

	private boolean[] free;

	private double[] value; // variable represents prescribed displacement
							// constraint

	protected FunctionRnToR lambda; // amplification factor at time t

	/**
	 * constructor
	 * 
	 * @param u1
	 *            array of values specify constraint state at each mode.
	 */
	public Constraint(boolean... u1) {
		if (u1 == null)
			throw new Error("Constraint is undefined!"); //$NON-NLS-1$
		this.free = u1;
		this.value = new double[u1.length];
		lambda = UnitFunctionRnToR.getInstance();
	}

	/**
	 * set fixed or free for constraint at field idx
	 * 
	 * @param idx
	 * @param free
	 */
	public void setFree(int idx, boolean free) {
		this.free[idx] = free;
	}

	/**
	 * @param idx
	 *            index of mode
	 * @return boolean value of constraint state associated with mode
	 *         <code>idx</code>
	 */
	public boolean isFree(int idx) {
		return this.free[idx];
	}

	/**
	 * set the value of constraint at mode <code>idx</code>
	 * 
	 * @param idx
	 * @param value
	 */
	public void setValue(int idx, double value) {
		this.value[idx] = value;
	}

	/**
	 * get value of original prescribed constraint
	 * 
	 * @param idx
	 * @return value of constraint at mode <code>idx</code>
	 */
	public double getValue(int idx) {
		return this.value[idx];
	}

	/**
	 * get value of prescribed constraint at time t
	 * 
	 * @param idx
	 * @return value of constraint at mode <code>idx</code>
	 */
	public double getValue(int idx, double t) {
		return this.value[idx] * lambda.valueAt(t);
	}

	/**
	 * set the time amplification factor for this load. By default, it's unity
	 * 
	 * @param lambda
	 */
	public void setTimeFactor(FunctionRnToR lambda) {
		this.lambda = lambda;
	}

	/**
	 * add this constraint with another constraint
	 * 
	 * @param c
	 */
	public void add(Constraint c) {
		for (int i = 0; i < this.free.length; i++) {
			this.free[i] &= c.isFree(i);
			if (!c.isFree(i)) {
				this.value[i] = c.getValue(i);
			}
		}
	}

	@Override
	public Object clone() {
		boolean[] free_ = free.clone();
		Constraint c = new Constraint(free_);
		for (int i = 0; i < value.length; i++) {
			c.setValue(i, value[i]);
		}
		return c;
	}
}
